/**
 * @file SocketIO.cc
 * @brief Socket IO操作类的实现
 */

#include "SocketIO.hpp"
#include "TLV.hpp"
#include <sys/socket.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <iostream>

namespace wd
{
using std::cout;

// 查看接收缓冲区数据（MSG_PEEK标志不移除数据）
int SocketIO::recvPeek(char * buff, int len) const
{
    int ret = -1;
    do{
        ret = recv(_fd, buff, len, MSG_PEEK);
    }while(ret == -1 && errno == EINTR); 
    return ret;
}

// 确保发送len个字节的数据    
int SocketIO::sendn(const char * buff, int len) const
{
    const char * pbuf = buff;
    int left = len;
    while(left > 0) {
        int ret = send(_fd, pbuf, left, 0);
        if(ret < 0) {
            perror("send");
            return ret;
        }

        left -= ret;
        pbuf += ret;
    }
    return len;
}

// 确保接收len个字节的数据
int SocketIO::readn(char * buff, int len) const
{
    char * pbuf = buff;
    int left = len;
    while(left > 0) {
        int ret = recv(_fd, pbuf, left, 0);
        if(ret == -1 && errno == EINTR)
            continue;
        else if(ret == -1) {
            perror("recv");
            return ret;
        }

        left -= ret;
        pbuf += ret;
    }
    return len;
}

// 按行读取数据（以'\n'为消息边界）
int SocketIO::readline(char * buff, int maxlen) const
{
    //将buff的最后一个位置的元素设置为'\0'
    //防止出现数据越界的情况
    int left = maxlen - 1;///
    char * pbuf = buff;
    int total = 0;
    while(left > 0) {
        //没有移走内核接收缓冲区中的数据
        int ret = recvPeek(pbuf, left);
        
        //查看这ret个字节中是否有'\n'
        for(int i = 0; i < ret; ++i) {
            //发现了\n
            if(pbuf[i] == '\n') {
                int sz = i + 1;
                ret = readn(pbuf, sz);
                total += ret;
                return total;
            }
        }
        //移走内核接收缓冲区中的数据
        ret = readn(pbuf, ret);
        //没有发现\n
        left -= ret;
        pbuf += ret;
        total += ret;
    }
    buff[maxlen - 1] = '\0';
    return maxlen - 1;
}

/*int SocketIO::readPacket(Packet &packet){*/      
/*    char buff[65536] = {0};*/
/*    int ret = readline(buff, sizeof(buff));*/
/*    string pac(buff, ret);*/
/*    /**/
/*    size_t pos = pac.find_last_of("\n");*/
/*    if (pos!= std::string::npos) {*/
/*        pac.erase(pos);*/
/*    }*/
/*    cout << "SocketIO::readPacket 未处理换行的原始stringsize:" << pac.size() << endl;*/
/*    packet = Packet::StringtoPacket(pac);*/
/*    //处理换行符*/
/*    size_t pos = packet._msg.find_last_of("\n");*/
/*    if (pos!= std::string::npos) {*/
/*        packet._msg.erase(pos);*/
/*        packet.length--;*/
/*    }*/

/*    cout << "Socket::readPacket recv packet info:" << packet._msg;*/
/*    cout << "SocketIO::readPacket packet length:" << packet.length << endl;*/
/*    return 1;*/


int SocketIO::readPacket(Packet &packet) {

    cout << "do SocketIO::readPacket " << endl;
    char buff[4096] = { 0 };
    //读TLVtype
    int readTypenum = readn(buff, sizeof(int));
    if (sizeof(int) != readTypenum) {
        MyLogger::getInstance().serverError("SocketIO::readPacket read TLV.Type error");
        return -1;
    }
    int dataType = *(int *)buff;
    //用于调试
    //cout << "TLV.Type:" << dataType << endl;


    //读TLVlength
    int readLengthnum = readn(buff + sizeof(int), sizeof(int));
    if (sizeof(int) != readLengthnum) {
        MyLogger::getInstance().serverError("SocketIO::readPacket read TLV.Length error");
        return -1;
    }

    int dataLength = *(int *)(buff + sizeof(int));
    //用于调试
    //cout << "TLV.Length:" << dataLength << endl;

    //读TLVdata
    int readDatanum = readn(buff + sizeof(int) * 2, dataLength);
    if (readDatanum != dataLength) {
        MyLogger::getInstance().serverError("SocketIO::readPacket read TLVdata error");
        cout << "readDatanum:" << readDatanum << endl;
        return -1;
    }

    //转TLV格式string
    string TLVstring(buff, dataLength + sizeof(int) * 2);
    //TLV转Packet
    packet = Packet::StringtoPacket(TLVstring);
    
    //用于调试
    /*
    //输出Packet的信息
    cout << "SocketIO::readPacket return Packet.message:" << packet._msg << endl;
    cout << "Packet.type:" << packet.type << endl;
    cout << "Packet.length:" << packet.length << endl;
    */
    return 1;
}



}
